<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta
            http-equiv="Content-Type"
            content="text/html; charset=utf-8"
        />
        <meta name="viewport" content="width=device-width, initial-scale=1" />

        <title>OAuth Modules &mdash; Python Slack SDK</title>

        <!-- Google Tag Manager -->
        <script>
            (function(w, d, s, l, i) {
                w[l] = w[l] || [];
                w[l].push({
                    'gtm.start': new Date().getTime(),
                    event: 'gtm.js'
                });
                var f = d.getElementsByTagName(s)[0],
                    j = d.createElement(s),
                    dl = l != 'dataLayer' ? '&l=' + l : '';
                j.async = true;
                j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
                f.parentNode.insertBefore(j, f);
            })(window, document, 'script', 'dataLayer', 'GTM-KFZ5MK7');
        </script>
        <!-- End Google Tag Manager -->
        
        <link
            href="https://a.slack-edge.com/4f227/style/rollup-slack_kit_legacy_adapters.css"
            rel="stylesheet"
            type="text/css"
        />
        <link
            href="https://a.slack-edge.com/3e02c0/style/rollup-api_site.css"
            rel="stylesheet"
            type="text/css"
        />
        <link
            rel="stylesheet"
            href=".././assets/default.css"
            type="text/css"
        />
        <link
            rel="stylesheet"
            href=".././assets/pygments.css"
            type="text/css"
        />
        <link
            rel="stylesheet"
            href=".././assets/docs.css"
            type="text/css"
        />
        <link
            id="favicon"
            rel="shortcut icon"
            href="https://a.slack-edge.com/4f28/img/icons/favicon-32.png"
            type="image/png"
        />
        <link
            rel="top"
            title="Python Slack SDK 1.0.1 documentation"
            href="../index.html"
        />
    </head>

    <body class="api light_theme">
        <!-- Google Tag Manager (noscript) -->
        <noscript
            ><iframe
                src="https://www.googletagmanager.com/ns.html?id=GTM-KFZ5MK7"
                height="0"
                width="0"
                style="display:none;visibility:hidden"
            ></iframe
        ></noscript>
        <!-- End Google Tag Manager (noscript) -->
        <header>
            <a id="menu_toggle" class="no_transition show_on_mobile">
                <span class="menu_icon"></span>
                <span class="vert_divider"></span>
            </a>
            <a
                href="https://api.slack.com/"
                id="header_logo"
                class="api hide_on_mobile"
                style="float:left; display: inline-block;"
            >
                <img
                    alt="Slack API"
                    src="https://a.slack-edge.com/3026cb/img/slack_api_logo_vogue.png"
                    style="width: 225px; padding-right: 25px; border-right: 1px solid #DDD;"
                />
            </a>
            <span
                style="display: inline-block; padding-left: 20px; margin-top: 25px; font-weight: bold;"
            >
                <a style="color: #555459;" href="./index.html">Python Slack SDK</a>
            </span>
            <div class="header_nav">
                <a
                    href="https://github.com/SlackAPI/python-slack-sdk"
                    class="btn header_btn float_right"
                    data-qa="go_to_slack"
                    >Go to GitHub</a
                >
            </div>
        </header>
        

        <div id="page">
            <div id="page_contents" class="clearfix">
                <!-- Sidebar Content -->
                <nav id="api_nav" class="col span_1_of_4">
                    <div id="api_sections">
                         <ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../index.html">Python Slack SDK</a></li>
<li class="toctree-l1"><a class="reference internal" href="../v3-migration/index.html">Migration Guide</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../v3-migration/index.html#from-slackclient-2-x">From slackclient 2.x</a></li>
<li class="toctree-l2"><a class="reference internal" href="../v3-migration/index.html#from-slackclient-1-x">From slackclient 1.x</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../installation/index.html">Installation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../installation/index.html#access-tokens">Access Tokens</a></li>
<li class="toctree-l2"><a class="reference internal" href="../installation/index.html#workspace-installations">Workspace Installations</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../web/index.html">Web Client</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../web/index.html#messaging">Messaging</a></li>
<li class="toctree-l2"><a class="reference internal" href="../web/index.html#files">Files</a></li>
<li class="toctree-l2"><a class="reference internal" href="../web/index.html#conversations">Conversations</a></li>
<li class="toctree-l2"><a class="reference internal" href="../web/index.html#modals">Modals</a></li>
<li class="toctree-l2"><a class="reference internal" href="../web/index.html#rate-limits">Rate Limits</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../web/index.html#calling-any-api-methods">Calling any API methods</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../web/index.html#asyncwebclient">AsyncWebClient</a></li>
<li class="toctree-l2"><a class="reference internal" href="../web/index.html#retryhandler">RetryHandler</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../webhook/index.html">Webhook Client</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../webhook/index.html#id1">Incoming Webhooks</a></li>
<li class="toctree-l2"><a class="reference internal" href="../webhook/index.html#response-url">response_url</a></li>
<li class="toctree-l2"><a class="reference internal" href="../webhook/index.html#asyncwebhookclient">AsyncWebhookClient</a></li>
<li class="toctree-l2"><a class="reference internal" href="../webhook/index.html#retryhandler">RetryHandler</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../socket-mode/index.html">Socket Mode Client</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../socket-mode/index.html#socketmodeclient">SocketModeClient</a></li>
<li class="toctree-l2"><a class="reference internal" href="../socket-mode/index.html#supported-libraries">Supported Libraries</a></li>
<li class="toctree-l2"><a class="reference internal" href="../socket-mode/index.html#asyncio-based-libraries">Asyncio Based Libraries</a></li>
</ul>
</li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">OAuth Modules</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#app-installation-flow">App Installation Flow</a></li>
<li class="toctree-l2"><a class="reference internal" href="#token-lookup">Token Lookup</a></li>
<li class="toctree-l2"><a class="reference internal" href="#sign-in-with-slack">Sign in with Slack</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../audit-logs/index.html">Audit Logs API Client</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../audit-logs/index.html#auditlogsclient">AuditLogsClient</a></li>
<li class="toctree-l2"><a class="reference internal" href="../audit-logs/index.html#asyncauditlogsclient">AsyncAuditLogsClient</a></li>
<li class="toctree-l2"><a class="reference internal" href="../audit-logs/index.html#retryhandler">RetryHandler</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../scim/index.html">SCIM API Client</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../scim/index.html#scimclient">SCIMClient</a></li>
<li class="toctree-l2"><a class="reference internal" href="../scim/index.html#asyncscimclient">AsyncSCIMClient</a></li>
<li class="toctree-l2"><a class="reference internal" href="../scim/index.html#retryhandler">RetryHandler</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../real_time_messaging.html">RTM Client</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../real_time_messaging.html#real-time-messaging-rtm">Real Time Messaging (RTM)</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../faq.html">FAQ</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../faq.html#python-documents">Python Documents</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq.html#installation-issues">Installation Issues</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq.html#bug-report">Bug Report</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq.html#feature-requests">Feature Requests</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq.html#contributions">Contributions</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq.html#documentation">Documentation</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../about.html">About</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../about.html#product-name">Python Slack SDK</a></li>
</ul>
</li>
</ul>


<div id="footer">

        <ul id="footer_nav">
                <li><a href="https://github.com/SlackAPI/python-slack-sdk/blob/main/LICENSE">License</a></li>
                <li><a href="https://slackhq.github.io/code-of-conduct">Code of Conduct</a></li>
                <li><a href="https://github.com/slackapi/python-slack-sdk/blob/main/.github/contributing.md">Contributing</a></li>
                <li><a href="https://docs.google.com/a/slack-corp.com/forms/d/e/1FAIpQLSfzjVoCM7ohBnjWf7eDYQxzti1EPpinsIJQA5RAUBwJKRUQHg/viewform">Contributor License Agreement</a></li>
        </ul>

        <p id="footer_signature">Made with <i class="ts_icon ts_icon_heart"></i> by Slack<br/>and our Lovely
                Community
        </p>
</div> 
                    </div>
                </nav>
                <!-- /Sidebar Content -->

                <!-- Body Content -->
                <div class="col span_3_of_4">
                    <!-- <div class="section-title">OAuth Modules</div> -->
                    <div class="card">
  <section id="oauth-modules">
<h1>OAuth Modules<a class="headerlink" href="#oauth-modules" title="Link to this heading">¶</a></h1>
<p>This section explains the details about how to handle Slack’s OAuth flow.</p>
<p>If you’re looking for a much easier way to do the same, check <a class="reference external" href="https://github.com/slackapi/bolt-python">Bolt for Python</a>, which is a full-stack Slack App framework. With Bolt, you don’t need to implement most of the following code on your own.</p>
<p>The Python document for this module is available at <a class="reference external" href="https://slack.dev/python-slack-sdk/api-docs/slack_sdk/">https://slack.dev/python-slack-sdk/api-docs/slack_sdk/</a></p>
<section id="app-installation-flow">
<h2>App Installation Flow<a class="headerlink" href="#app-installation-flow" title="Link to this heading">¶</a></h2>
<p>OAuth lets a user in any Slack workspace install your app. At the end of OAuth, your app gains an access token. Refer to <a class="reference external" href="https://api.slack.com/authentication/oauth-v2">Installing with OAuth</a> for details.</p>
<p>Python Slack SDK provides the necessary modules for building the OAuth flow.</p>
<p><strong>Starting an OAuth flow</strong></p>
<p>The first step of Slack OAuth flow is to redirect a Slack user to <a class="reference external" href="https://slack.com/oauth/v2/authorize">https://slack.com/oauth/v2/authorize</a> with a valida <code class="docutils literal notranslate"><span class="pre">state</span></code> parameter. To implement this process, you can use the following modules.</p>
<table class="docutils align-default">
<tbody>
<tr class="row-odd"><td><p>Module</p></td>
<td><p>What its for</p></td>
<td><p>Default Implementation</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">InstallationStore</span></code></p></td>
<td><p>Persist installation data and lookup it by IDs.</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">FileInstallationStore</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">OAuthStateStore</span></code></p></td>
<td><p>Issue and consume <code class="docutils literal notranslate"><span class="pre">state</span></code> parameter value on the server-side.</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">FileOAuthStateStore</span></code></p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">AuthorizeUrlGenerator</span></code></p></td>
<td><p>Build <a class="reference external" href="https://slack.com/oauth/v2/authorize">https://slack.com/oauth/v2/authorize</a> with sufficient query parameters</p></td>
<td><p>(same)</p></td>
</tr>
</tbody>
</table>
<p>The code snippet below demonstrates how to build it using <a class="reference external" href="https://flask.palletsprojects.com/">Flask</a>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">html</span>
<span class="kn">from</span> <span class="nn">slack_sdk.oauth</span> <span class="kn">import</span> <span class="n">AuthorizeUrlGenerator</span>
<span class="kn">from</span> <span class="nn">slack_sdk.oauth.installation_store</span> <span class="kn">import</span> <span class="n">FileInstallationStore</span><span class="p">,</span> <span class="n">Installation</span>
<span class="kn">from</span> <span class="nn">slack_sdk.oauth.state_store</span> <span class="kn">import</span> <span class="n">FileOAuthStateStore</span>

<span class="c1"># Issue and consume state parameter value on the server-side.</span>
<span class="n">state_store</span> <span class="o">=</span> <span class="n">FileOAuthStateStore</span><span class="p">(</span><span class="n">expiration_seconds</span><span class="o">=</span><span class="mi">300</span><span class="p">,</span> <span class="n">base_dir</span><span class="o">=</span><span class="s2">&quot;./data&quot;</span><span class="p">)</span>
<span class="c1"># Persist installation data and lookup it by IDs.</span>
<span class="n">installation_store</span> <span class="o">=</span> <span class="n">FileInstallationStore</span><span class="p">(</span><span class="n">base_dir</span><span class="o">=</span><span class="s2">&quot;./data&quot;</span><span class="p">)</span>

<span class="c1"># Build https://slack.com/oauth/v2/authorize with sufficient query parameters</span>
<span class="n">authorize_url_generator</span> <span class="o">=</span> <span class="n">AuthorizeUrlGenerator</span><span class="p">(</span>
    <span class="n">client_id</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">&quot;SLACK_CLIENT_ID&quot;</span><span class="p">],</span>
    <span class="n">scopes</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;app_mentions:read&quot;</span><span class="p">,</span> <span class="s2">&quot;chat:write&quot;</span><span class="p">],</span>
    <span class="n">user_scopes</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;search:read&quot;</span><span class="p">],</span>
<span class="p">)</span>

<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">make_response</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>

<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/slack/install&quot;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;GET&quot;</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">oauth_start</span><span class="p">():</span>
    <span class="c1"># Generate a random value and store it on the server-side</span>
    <span class="n">state</span> <span class="o">=</span> <span class="n">state_store</span><span class="o">.</span><span class="n">issue</span><span class="p">()</span>
    <span class="c1"># https://slack.com/oauth/v2/authorize?state=(generated value)&amp;client_id={client_id}&amp;scope=app_mentions:read,chat:write&amp;user_scope=search:read</span>
    <span class="n">url</span> <span class="o">=</span> <span class="n">authorize_url_generator</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
    <span class="k">return</span> <span class="sa">f</span><span class="s1">&#39;&lt;a href=&quot;</span><span class="si">{</span><span class="n">html</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><span class="si">}</span><span class="s1">&quot;&gt;&#39;</span> \
           <span class="sa">f</span><span class="s1">&#39;&lt;img alt=&quot;&quot;Add to Slack&quot;&quot; height=&quot;40&quot; width=&quot;139&quot; src=&quot;https://platform.slack-edge.com/img/add_to_slack.png&quot; srcset=&quot;https://platform.slack-edge.com/img/add_to_slack.png 1x, https://platform.slack-edge.com/img/add_to_slack@2x.png 2x&quot; /&gt;&lt;/a&gt;&#39;</span>
</pre></div>
</div>
<p>When accessing <code class="docutils literal notranslate"><span class="pre">https://(your</span> <span class="pre">domain)/slack/install</span></code>, you will see “Add to Slack” button in the webpage. You can start the app’s installation flow by clicking the button.</p>
<p><strong>Handling a callback request from Slack</strong></p>
<p>If all’s well, a user goes through the Slack app installation UI and okays your app with all the scopes that it requests. After that happens, Slack redirects the user back to your specified Redirect URL.</p>
<p>The redirection gives you a <code class="docutils literal notranslate"><span class="pre">code</span></code> parameter. You can exchange the value for an access token by calling <a class="reference external" href="https://api.slack.com/methods/oauth.v2.access">oauth.v2.access</a> API method.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">slack_sdk.web</span> <span class="kn">import</span> <span class="n">WebClient</span>
<span class="n">client_secret</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">&quot;SLACK_CLIENT_SECRET&quot;</span><span class="p">]</span>

<span class="c1"># Redirect URL</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/slack/oauth/callback&quot;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;GET&quot;</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">oauth_callback</span><span class="p">():</span>
    <span class="c1"># Retrieve the auth code and state from the request params</span>
    <span class="k">if</span> <span class="s2">&quot;code&quot;</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="p">:</span>
        <span class="c1"># Verify the state parameter</span>
        <span class="k">if</span> <span class="n">state_store</span><span class="o">.</span><span class="n">consume</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]):</span>
            <span class="n">client</span> <span class="o">=</span> <span class="n">WebClient</span><span class="p">()</span>  <span class="c1"># no prepared token needed for this</span>
            <span class="c1"># Complete the installation by calling oauth.v2.access API method</span>
            <span class="n">oauth_response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">oauth_v2_access</span><span class="p">(</span>
                <span class="n">client_id</span><span class="o">=</span><span class="n">client_id</span><span class="p">,</span>
                <span class="n">client_secret</span><span class="o">=</span><span class="n">client_secret</span><span class="p">,</span>
                <span class="n">redirect_uri</span><span class="o">=</span><span class="n">redirect_uri</span><span class="p">,</span>
                <span class="n">code</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="s2">&quot;code&quot;</span><span class="p">]</span>
            <span class="p">)</span>
            <span class="n">installed_enterprise</span> <span class="o">=</span> <span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;enterprise&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{}</span>
            <span class="n">is_enterprise_install</span> <span class="o">=</span> <span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;is_enterprise_install&quot;</span><span class="p">)</span>
            <span class="n">installed_team</span> <span class="o">=</span> <span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;team&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{}</span>
            <span class="n">installer</span> <span class="o">=</span> <span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;authed_user&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{}</span>
            <span class="n">incoming_webhook</span> <span class="o">=</span> <span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;incoming_webhook&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{}</span>
            <span class="n">bot_token</span> <span class="o">=</span> <span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;access_token&quot;</span><span class="p">)</span>
            <span class="c1"># NOTE: oauth.v2.access doesn&#39;t include bot_id in response</span>
            <span class="n">bot_id</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">enterprise_url</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="k">if</span> <span class="n">bot_token</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
                <span class="n">auth_test</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">auth_test</span><span class="p">(</span><span class="n">token</span><span class="o">=</span><span class="n">bot_token</span><span class="p">)</span>
                <span class="n">bot_id</span> <span class="o">=</span> <span class="n">auth_test</span><span class="p">[</span><span class="s2">&quot;bot_id&quot;</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">is_enterprise_install</span> <span class="ow">is</span> <span class="kc">True</span><span class="p">:</span>
                    <span class="n">enterprise_url</span> <span class="o">=</span> <span class="n">auth_test</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;url&quot;</span><span class="p">)</span>

            <span class="n">installation</span> <span class="o">=</span> <span class="n">Installation</span><span class="p">(</span>
                <span class="n">app_id</span><span class="o">=</span><span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;app_id&quot;</span><span class="p">),</span>
                <span class="n">enterprise_id</span><span class="o">=</span><span class="n">installed_enterprise</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;id&quot;</span><span class="p">),</span>
                <span class="n">enterprise_name</span><span class="o">=</span><span class="n">installed_enterprise</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">),</span>
                <span class="n">enterprise_url</span><span class="o">=</span><span class="n">enterprise_url</span><span class="p">,</span>
                <span class="n">team_id</span><span class="o">=</span><span class="n">installed_team</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;id&quot;</span><span class="p">),</span>
                <span class="n">team_name</span><span class="o">=</span><span class="n">installed_team</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">),</span>
                <span class="n">bot_token</span><span class="o">=</span><span class="n">bot_token</span><span class="p">,</span>
                <span class="n">bot_id</span><span class="o">=</span><span class="n">bot_id</span><span class="p">,</span>
                <span class="n">bot_user_id</span><span class="o">=</span><span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;bot_user_id&quot;</span><span class="p">),</span>
                <span class="n">bot_scopes</span><span class="o">=</span><span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;scope&quot;</span><span class="p">),</span>  <span class="c1"># comma-separated string</span>
                <span class="n">user_id</span><span class="o">=</span><span class="n">installer</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;id&quot;</span><span class="p">),</span>
                <span class="n">user_token</span><span class="o">=</span><span class="n">installer</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;access_token&quot;</span><span class="p">),</span>
                <span class="n">user_scopes</span><span class="o">=</span><span class="n">installer</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;scope&quot;</span><span class="p">),</span>  <span class="c1"># comma-separated string</span>
                <span class="n">incoming_webhook_url</span><span class="o">=</span><span class="n">incoming_webhook</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;url&quot;</span><span class="p">),</span>
                <span class="n">incoming_webhook_channel</span><span class="o">=</span><span class="n">incoming_webhook</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;channel&quot;</span><span class="p">),</span>
                <span class="n">incoming_webhook_channel_id</span><span class="o">=</span><span class="n">incoming_webhook</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;channel_id&quot;</span><span class="p">),</span>
                <span class="n">incoming_webhook_configuration_url</span><span class="o">=</span><span class="n">incoming_webhook</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;configuration_url&quot;</span><span class="p">),</span>
                <span class="n">is_enterprise_install</span><span class="o">=</span><span class="n">is_enterprise_install</span><span class="p">,</span>
                <span class="n">token_type</span><span class="o">=</span><span class="n">oauth_response</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;token_type&quot;</span><span class="p">),</span>
            <span class="p">)</span>

            <span class="c1"># Store the installation</span>
            <span class="n">installation_store</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">installation</span><span class="p">)</span>

            <span class="k">return</span> <span class="s2">&quot;Thanks for installing this app!&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Try the installation again (the state value is already expired)&quot;</span><span class="p">,</span> <span class="mi">400</span><span class="p">)</span>

    <span class="n">error</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="s2">&quot;error&quot;</span><span class="p">]</span> <span class="k">if</span> <span class="s2">&quot;error&quot;</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">args</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
    <span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Something is wrong with the installation (error: </span><span class="si">{</span><span class="n">html</span><span class="o">.</span><span class="n">escape</span><span class="p">(</span><span class="n">error</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">,</span> <span class="mi">400</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="token-lookup">
<h2>Token Lookup<a class="headerlink" href="#token-lookup" title="Link to this heading">¶</a></h2>
<p>Now that your Flask app can choose the right access token for incoming event requests, let’s add the Slack event handler endpoint.</p>
<p>You can use the same <code class="docutils literal notranslate"><span class="pre">InstallationStore</span></code> in the Slack event handler.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">json</span>
<span class="kn">from</span> <span class="nn">slack_sdk.errors</span> <span class="kn">import</span> <span class="n">SlackApiError</span>

<span class="kn">from</span> <span class="nn">slack_sdk.signature</span> <span class="kn">import</span> <span class="n">SignatureVerifier</span>
<span class="n">signing_secret</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">&quot;SLACK_SIGNING_SECRET&quot;</span><span class="p">]</span>
<span class="n">signature_verifier</span> <span class="o">=</span> <span class="n">SignatureVerifier</span><span class="p">(</span><span class="n">signing_secret</span><span class="o">=</span><span class="n">signing_secret</span><span class="p">)</span>

<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">&quot;/slack/events&quot;</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;POST&quot;</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">slack_app</span><span class="p">():</span>
    <span class="c1"># Verify incoming requests from Slack</span>
    <span class="c1"># https://api.slack.com/authentication/verifying-requests-from-slack</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">signature_verifier</span><span class="o">.</span><span class="n">is_valid</span><span class="p">(</span>
        <span class="n">body</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">get_data</span><span class="p">(),</span>
        <span class="n">timestamp</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;X-Slack-Request-Timestamp&quot;</span><span class="p">),</span>
        <span class="n">signature</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;X-Slack-Signature&quot;</span><span class="p">)):</span>
        <span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="s2">&quot;invalid request&quot;</span><span class="p">,</span> <span class="mi">403</span><span class="p">)</span>

    <span class="c1"># Handle a slash command invocation</span>
    <span class="k">if</span> <span class="s2">&quot;command&quot;</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span> \
        <span class="ow">and</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s2">&quot;command&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;/open-modal&quot;</span><span class="p">:</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="c1"># in the case where this app gets a request from an Enterprise Grid workspace</span>
            <span class="n">enterprise_id</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;enterprise_id&quot;</span><span class="p">)</span>
            <span class="c1"># The workspace&#39;s ID</span>
            <span class="n">team_id</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s2">&quot;team_id&quot;</span><span class="p">]</span>
            <span class="c1"># Lookup the stored bot token for this workspace</span>
            <span class="n">bot</span> <span class="o">=</span> <span class="n">installation_store</span><span class="o">.</span><span class="n">find_bot</span><span class="p">(</span>
                <span class="n">enterprise_id</span><span class="o">=</span><span class="n">enterprise_id</span><span class="p">,</span>
                <span class="n">team_id</span><span class="o">=</span><span class="n">team_id</span><span class="p">,</span>
            <span class="p">)</span>
            <span class="n">bot_token</span> <span class="o">=</span> <span class="n">bot</span><span class="o">.</span><span class="n">bot_token</span> <span class="k">if</span> <span class="n">bot</span> <span class="k">else</span> <span class="kc">None</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">bot_token</span><span class="p">:</span>
                <span class="c1"># The app may be uninstalled or be used in a shared channel</span>
                <span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="s2">&quot;Please install this app first!&quot;</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>

            <span class="c1"># Open a modal using the valid bot token</span>
            <span class="n">client</span> <span class="o">=</span> <span class="n">WebClient</span><span class="p">(</span><span class="n">token</span><span class="o">=</span><span class="n">bot_token</span><span class="p">)</span>
            <span class="n">trigger_id</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s2">&quot;trigger_id&quot;</span><span class="p">]</span>
            <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">views_open</span><span class="p">(</span>
                <span class="n">trigger_id</span><span class="o">=</span><span class="n">trigger_id</span><span class="p">,</span>
                <span class="n">view</span><span class="o">=</span><span class="p">{</span>
                    <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;modal&quot;</span><span class="p">,</span>
                    <span class="s2">&quot;callback_id&quot;</span><span class="p">:</span> <span class="s2">&quot;modal-id&quot;</span><span class="p">,</span>
                    <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="p">{</span>
                        <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;plain_text&quot;</span><span class="p">,</span>
                        <span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="s2">&quot;Awesome Modal&quot;</span>
                    <span class="p">},</span>
                    <span class="s2">&quot;submit&quot;</span><span class="p">:</span> <span class="p">{</span>
                        <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;plain_text&quot;</span><span class="p">,</span>
                        <span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="s2">&quot;Submit&quot;</span>
                    <span class="p">},</span>
                    <span class="s2">&quot;blocks&quot;</span><span class="p">:</span> <span class="p">[</span>
                        <span class="p">{</span>
                            <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;input&quot;</span><span class="p">,</span>
                            <span class="s2">&quot;block_id&quot;</span><span class="p">:</span> <span class="s2">&quot;b-id&quot;</span><span class="p">,</span>
                            <span class="s2">&quot;label&quot;</span><span class="p">:</span> <span class="p">{</span>
                                <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;plain_text&quot;</span><span class="p">,</span>
                                <span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="s2">&quot;Input label&quot;</span><span class="p">,</span>
                            <span class="p">},</span>
                            <span class="s2">&quot;element&quot;</span><span class="p">:</span> <span class="p">{</span>
                                <span class="s2">&quot;action_id&quot;</span><span class="p">:</span> <span class="s2">&quot;a-id&quot;</span><span class="p">,</span>
                                <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;plain_text_input&quot;</span><span class="p">,</span>
                            <span class="p">}</span>
                        <span class="p">}</span>
                    <span class="p">]</span>
                <span class="p">}</span>
            <span class="p">)</span>
            <span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>
        <span class="k">except</span> <span class="n">SlackApiError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="n">code</span> <span class="o">=</span> <span class="n">e</span><span class="o">.</span><span class="n">response</span><span class="p">[</span><span class="s2">&quot;error&quot;</span><span class="p">]</span>
            <span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to open a modal due to </span><span class="si">{</span><span class="n">code</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>

    <span class="k">elif</span> <span class="s2">&quot;payload&quot;</span> <span class="ow">in</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">:</span>
        <span class="c1"># Data submission from the modal</span>
        <span class="n">payload</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s2">&quot;payload&quot;</span><span class="p">])</span>
        <span class="k">if</span> <span class="n">payload</span><span class="p">[</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;view_submission&quot;</span> \
            <span class="ow">and</span> <span class="n">payload</span><span class="p">[</span><span class="s2">&quot;view&quot;</span><span class="p">][</span><span class="s2">&quot;callback_id&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;modal-id&quot;</span><span class="p">:</span>
            <span class="n">submitted_data</span> <span class="o">=</span> <span class="n">payload</span><span class="p">[</span><span class="s2">&quot;view&quot;</span><span class="p">][</span><span class="s2">&quot;state&quot;</span><span class="p">][</span><span class="s2">&quot;values&quot;</span><span class="p">]</span>
            <span class="nb">print</span><span class="p">(</span><span class="n">submitted_data</span><span class="p">)</span>  <span class="c1"># {&#39;b-id&#39;: {&#39;a-id&#39;: {&#39;type&#39;: &#39;plain_text_input&#39;, &#39;value&#39;: &#39;your input&#39;}}}</span>
            <span class="c1"># You can use WebClient with a valid token here too</span>
            <span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="mi">200</span><span class="p">)</span>

    <span class="c1"># Indicate unsupported request patterns</span>
    <span class="k">return</span> <span class="n">make_response</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="mi">404</span><span class="p">)</span>
</pre></div>
</div>
<p>Again, if you’re looking for an easier solution, take a look at <a class="reference external" href="https://github.com/slackapi/bolt-python">Bolt for Python</a>. With Bolt, you don’t need to implement most of the above code on your own.</p>
</section>
<section id="sign-in-with-slack">
<h2>Sign in with Slack<a class="headerlink" href="#sign-in-with-slack" title="Link to this heading">¶</a></h2>
<p><a class="reference external" href="https://api.slack.com/authentication/sign-in-with-slack">Sign in with Slack</a> helps users log into your service using their Slack profile. The platform feature was recently upgraded to be compatible with the standard <a class="reference external" href="https://openid.net/connect/">OpenID Connect</a> specification. With slack-sdk v3.9+, implementing the auth flow is much easier.</p>
<p>When you create a new Slack app, set the following user scopes:</p>
<div class="highlight-yaml notranslate"><div class="highlight"><pre><span></span><span class="nt">oauth_config</span><span class="p">:</span>
<span class="w">  </span><span class="nt">redirect_urls</span><span class="p">:</span>
<span class="w">    </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">https://{your-domain}/slack/oauth_redirect</span>
<span class="w">  </span><span class="nt">scopes</span><span class="p">:</span>
<span class="w">    </span><span class="nt">user</span><span class="p">:</span>
<span class="w">      </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">openid</span><span class="w">   </span><span class="c1"># required</span>
<span class="w">      </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">email</span><span class="w">    </span><span class="c1"># optional</span>
<span class="w">      </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">profile</span><span class="w">  </span><span class="c1"># optional</span>
</pre></div>
</div>
<p>Check <a class="reference external" href="https://github.com/slackapi/python-slack-sdk/blob/main/integration_tests/samples/openid_connect/flask_example.py">the Flask app example</a> to learn how to implement your Web app that handles the OpenID Connect flow with end-users. It does the following:</p>
<p><strong>Build the OpenID Connect authorize URL</strong></p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">slack_sdk.oauth.OpenIDConnectAuthorizeUrlGenerator</span></code> helps you easily do this</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">slack_sdk.oauth.OAuthStateStore</span></code> is still available for generating <code class="docutils literal notranslate"><span class="pre">state</span></code> parameter value. It’s available for <code class="docutils literal notranslate"><span class="pre">nonce</span></code> management too.</p></li>
</ul>
<p><strong>openid.connect.* API calls</strong></p>
<p><code class="docutils literal notranslate"><span class="pre">WebClient</span></code> can perform <code class="docutils literal notranslate"><span class="pre">openid.connect.token</span></code> API calls with given <code class="docutils literal notranslate"><span class="pre">code</span></code> parameter</p>
<p>If you want to know the way with asyncio, check <a class="reference external" href="https://github.com/slackapi/python-slack-sdk/blob/main/integration_tests/samples/openid_connect/sanic_example.py">the Sanic app example</a> in the same directory.</p>
</section>
</section>


                        <div class="clear_both large_bottom_margin"></div>
                    </div>
                </div>
                <!-- /Body Content -->
            </div>
        </div>

        <footer>
            <p class="light tiny align_center">
                © 2015- Slack Technologies, LLC and contributors
            </p>
        </footer>

        <script>
            window.ga =
                window.ga ||
                function() {
                    (ga.q = ga.q || []).push(arguments);
                };
            ga.l = +new Date();
            ga('create', 'UA-56978219-13', 'auto');
            ga('send', 'pageview');
        </script>
        <script async src="https://www.google-analytics.com/analytics.js"></script>
    </body>
</html>